/*
 * Copyright (c) KylinSoft Co., Ltd. 2025. All rights reserved.
 * See COPYRIGHT file for more details.
 */
package commands

import (
	"fmt"
	"os"
	"path"
	"runtime"
	"strconv"

	"bitbucket.org/creachadair/shell"
	rd "github.com/chzyer/readline"
	"github.com/fatih/color"
	dbcli "github.com/liderman/leveldb-cli/commands"
	"github.com/spf13/cobra"
)

const VERSION = "1.0.0"
const (
	dbCliName     = "database"
	dbDirPath     = "./db/ant-agent.db"
	dbHistoryFile = "./tmp/ant-agentdb.tmp"
)

const (
	COMMAND_SHOW      = "show"
	COMMAND_PREFIX    = "prefix"
	COMMAND_RANGE     = "range"
	COMMAND_HELP      = "help"
	COMMAND_GET       = "get"
	COMMAND_EXPORT    = "export"
	COMMAND_PUT       = "put"
	COMMAND_EXIT      = "exit"
	COMMAND_QUIT      = "quit"
	COMMAND_SET       = "set"
	COMMAND_DELETE    = "delete"
	COMMAND_VERSION   = "version"
	COMMAND_LIMIT     = "limit"
	COMMAND_COUNT     = "count"
	COMMAND_CLOSE     = "close"
	COMMAND_OPEN      = "open"
	COMMAND_OPENOTHER = "openpath"
)

var prefixCompleter = rd.NewPrefixCompleter(
	rd.PcItem(COMMAND_SHOW,
		rd.PcItem(COMMAND_PREFIX),
		rd.PcItem(COMMAND_RANGE),
	),
	rd.PcItem(COMMAND_HELP),
	rd.PcItem(COMMAND_GET),
	rd.PcItem(COMMAND_EXPORT),
	rd.PcItem(COMMAND_PUT),
	rd.PcItem(COMMAND_EXIT),
	rd.PcItem(COMMAND_QUIT),
	rd.PcItem(COMMAND_SET),
	rd.PcItem(COMMAND_DELETE),
	rd.PcItem(COMMAND_VERSION),
	rd.PcItem(COMMAND_OPENOTHER),
)

func NewDbCliCommand() *cobra.Command {
	cmd := &cobra.Command{
		Example: `
		# database
		ant-agent database
		open
		help
		`,
		Use:   dbCliName,
		Short: "the ant-agent database command",
		RunE: func(cmd *cobra.Command, args []string) error {
			return dbCliRun()
		},
	}
	cmd.ResetFlags()
	return cmd
}

func dbCliRun() error {
	cr := color.New(color.FgBlue).Sprint(">>")
	crFormat := color.New(color.FgBlue).Sprintf("%s>>", path.Base(dbDirPath))
	rl, err := rd.NewEx(&rd.Config{
		Prompt:       cr,
		HistoryFile:  dbHistoryFile,
		AutoComplete: prefixCompleter,
	})
	if err != nil {
		panic(err)
	}
	defer rl.Close()
	fmt.Println("*********************************************************")
	fmt.Println("**                     Ant-agent DB CLI                     **")
	fmt.Println("*********************************************************")
	fmt.Println("Please Run command 'help' for help.")
	for {
		lineData, err := rl.Readline()
		if err != nil {
			break
		}
		osArgs, _ := shell.Split(lineData)
		switch {
		case lineData == COMMAND_VERSION:
			fmt.Printf("Version %s. %s %s %s\n", VERSION, runtime.Compiler, runtime.GOARCH, runtime.GOOS)
		case lineData == COMMAND_HELP:
			fmt.Println("Please Enter one of the commands to get help: show, set, get, export, open, openpath, close, put, delete, version")
		case lineData == COMMAND_QUIT:
		case lineData == COMMAND_EXIT:
			goto exit
		case len(osArgs) == 0:
		case osArgs[0] == COMMAND_SHOW:
			if len(osArgs) == 1 {
				fmt.Println("This is  Bad format. Please use 'show prefix|range|limit'")
				break
			}
			switch osArgs[1] {
			case COMMAND_RANGE:
				if len(osArgs) < 4 || len(osArgs) > 5 {
					fmt.Println("This is Bad format. Please use 'show range START LIMIT [FORMAT]'")
					break
				}
				format := ""
				if len(osArgs) == 5 {
					format = osArgs[4]
				}

				fmt.Println(dbcli.ShowByRange(osArgs[2], osArgs[3], format))
			case COMMAND_PREFIX:
				if len(osArgs) < 3 || len(osArgs) > 4 {
					fmt.Println("This is  Bad format. Please use 'show prefix PREFIX [FORMAT]'")
					break
				}
				format := ""
				if len(osArgs) == 4 {
					format = osArgs[3]
				}
				fmt.Println(dbcli.ShowByPrefix(osArgs[2], format))
			case COMMAND_LIMIT:
				if len(osArgs) < 3 || len(osArgs) > 4 {
					fmt.Println("This is Bad format. Please use 'show limit LIMIT [FORMAT]'")
					break
				}
				limit, err := strconv.Atoi(osArgs[2])
				if err != nil {
					fmt.Println("This is Bad LIMIT value. LIMIT must be a number")
					break
				}
				format := ""
				if len(osArgs) == 4 {
					format = osArgs[3]
				}
				fmt.Println(dbcli.ShowLimit(limit, format))
			case COMMAND_COUNT:
				if len(osArgs) < 2 || len(osArgs) > 3 {
					fmt.Println("This is Bad format. Please use'show count [FORMAT]'")
					break
				}
				fmt.Println(dbcli.ShowCount())
			default:
				fmt.Println("This is Bad format. Please use 'show prefix|range|limit'")
			}
		case osArgs[0] == COMMAND_PUT:
		case osArgs[0] == COMMAND_SET:
			if len(osArgs) != 3 {
				fmt.Printf("This is Bad format. Please use '%s KEY VALUE'\n", osArgs[0])
				break
			}
			fmt.Println(dbcli.Set(osArgs[1], osArgs[2]))
		case osArgs[0] == COMMAND_GET:
			if len(osArgs) < 2 || len(osArgs) > 3 {
				fmt.Println("This is Bad format. Please use 'get KEY FORMAT'")
				break
			}
			format := ""
			if len(osArgs) == 3 {
				format = osArgs[2]
			}
			fmt.Println(dbcli.Get(osArgs[1], format))
		case osArgs[0] == COMMAND_EXPORT:
			if len(osArgs) != 3 {
				fmt.Println("This is Bad format. Please use 'export KEY FILENAME'")
				break
			}
			fmt.Println(dbcli.Export(osArgs[1], osArgs[2]))
		case osArgs[0] == COMMAND_DELETE:
			if len(osArgs) != 2 {
				fmt.Print("This is Bad format. Please use 'delete KEY'")
				break
			}
			fmt.Println(dbcli.Delete(osArgs[1]))
		case osArgs[0] == COMMAND_CLOSE:
			if len(osArgs) != 1 {
				fmt.Print("This is Bad format. Please use 'close'")
				break
			}
			rl.SetPrompt(cr)
			fmt.Println(dbcli.Close())
		case osArgs[0] == COMMAND_OPENOTHER:
			_, err := os.Stat(osArgs[1])
			if err != nil {
				fmt.Println("Database not exist! Create new database.")
			}
			if len(osArgs) != 2 {
				fmt.Println("This is Bad format. Please use 'open DATABASE_NAME'")
				break
			}
			crFormatPrompt := color.New(color.FgBlue).Sprintf("%s>>", path.Base(osArgs[1]))
			rl.SetPrompt(crFormatPrompt)
			fmt.Println(dbcli.Open(osArgs[1]))
		case osArgs[0] == COMMAND_OPEN:
			_, err := os.Stat(dbDirPath)
			if err != nil {
				fmt.Println("This Database not exist! Create new database.")
			}
			rl.SetPrompt(crFormat)
			fmt.Println(dbcli.Open(dbDirPath))
		default:
			fmt.Println("This is Unknown command: ", strconv.Quote(lineData))
		}
	}
exit:
	return nil
}
